//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2003-2007
// ALAN and ALAN Map 500 are registered trademarks of ALAN Group.
//
// ALAN Map 500/600 WPR waypoints parser.
//

# include "StdAfx.h"
# include "AlanWpr.h"
# include "Map.h"
# include "Types.h"
# include "Load.h"
# include "Log.h"
# include "Status.h"
# include "ParseHelpers.h"
# include "Wrappers.h"
# include "Globals.h"

class CAlanWprLoader : public CMapLoader {
  public:
	// Override.
	virtual bool IsValid (const char * _pData, size_t _cFileSize) const;
	virtual LoadStatus_t Load (const char * _pData, size_t _cFileSize, const char * _strFileName, map_t * _pMap);
};

DECLARE_WPTRK_LOADER (CAlanWprLoader, "alan-wpr", "wpr", "ALAN Map 500/600 waypoints (*.wpr)", ftiWpts | ftiRoutes);

bool CAlanWprLoader::IsValid (const char * _pData, size_t _cFileSize) const {
	const CWprFile * const pWpr = reinterpret_cast<const CWprFile *> (_pData);
	if (_cFileSize < sizeof (CWprFile) - sizeof (pWpr->unused))
		return false;

	if (pWpr->WptHdr.dwSignature != c_dwWprWptSignature)
		return false;

	return true;
}

LoadStatus_t CAlanWprLoader::Load (const char * _pData, size_t _cFileSize, const char * _strFileName, map_t * _pMap) {
	const char * const pEnd = _pData + _cFileSize;

	file_refs_t file_refs;
	file_refs.push_back (file_ref_t ());
	file_refs.back ().strFileName = _strFileName;
	file_refs.back ().bAttachment = true;

	// Get time zone shift.
	TIME_ZONE_INFORMATION tzi;
	if (::GetTimeZoneInformation (& tzi) == TIME_ZONE_ID_DAYLIGHT)
		tzi.Bias += tzi.DaylightBias;
	const double dtTimeShift = float (tzi.Bias)/(24*60);

	SetProgressStatus (0);

	rgn_t * pWaypoints [c_cWprMaxWaypoints];
	::memset (pWaypoints, 0, sizeof (pWaypoints));

	const CWprFile * const pWprFile = reinterpret_cast<const CWprFile *> (_pData);

	// Waypoints.
	for (size_t cWpt = 0; cWpt < pWprFile->WptHdr.wCurrentWaypoints && cWpt < c_cWprMaxWaypoints; ++ cWpt) {
		const WORD wIdx = pWprFile->WptHdr.wIdx [cWpt];
		if (wIdx == 0xFFFF) {
			assert (pWprFile->WptHdr.btUsed [wIdx] == 0x00);
			continue;
		}
		assert (pWprFile->WptHdr.btUsed [wIdx] == 0xFF);
		const CWprWaypoint & wpt = pWprFile->Waypoints [wIdx];

		//
		// Create waypoint.
		//
		rgn_t & rgn = _pMap->CreateRgn (rkPoint);

		rgn.SetWaypointType ();

		rgn.pFileRef  = & file_refs.back ();
		rgn.cBeginPos = reinterpret_cast<const char *> (& wpt) - _pData;
		rgn.cEndPos   = pEnd - _pData;
		rgn.cFileLine = -1;

		// Name.
		rgn.strLabel.assign   (wpt.strName,    GetLineLen (wpt.strName,    wpt.strName    + sizeof (wpt.strName)));
		// Comment.
		rgn.strComment.assign (wpt.strComment, GetLineLen (wpt.strComment, wpt.strComment + sizeof (wpt.strComment)));

		// Position.
		rgn.origins.push_back (rgn_origin_t ());
		rgn_origin_t & origin = rgn.origins.back ();
		origin.cLevel      = 0;
		origin.cFileOffset = rgn.cBeginPos;
		origin.point.x =  wpt.lX/36000.f;
		origin.point.y = -wpt.lY/36000.f;

		// Extra.
		waypoint_info_t * const pExtra = rgn.pExtra->wtr.CreateWaypoint ();

		// Active.
		if (wpt.btActive)
			pExtra->SetShow (waypoint_info_t::showName);
		else
			pExtra->SetShow (waypoint_info_t::showHide);

		// Date and Time.
		const int nDay    =   wpt.dwDate       & 0x1F;
		const int nMonth  = ((wpt.dwDate >> 8) & 0xF);
		const int nYear   =  (wpt.dwDate >> 16);

		const int nSecond =  wpt.dwTime       % 60;
		const int nMinute = (wpt.dwTime/60)   % 60;
		const int nHour   = (wpt.dwTime/3600) % 60;

		SYSTEMTIME st = {nYear, nMonth, 0, nDay, nHour, nMinute, nSecond, 0};
		if (::SystemTimeToVariantTime (& st, & pExtra->dtTime)) {
			pExtra->dtTime += dtTimeShift;
			pExtra->wFlags |= waypoint_info_t::defTime;
		}

		pWaypoints [wIdx] = & rgn;

		SetProgressStatus (25*cWpt/pWprFile->WptHdr.wCurrentWaypoints);
	}

	// Routes.
	if (pWprFile->RoutesHdr.dwSignature == c_dwWprRoutesSignature) {
		for (size_t cRt = 0; cRt < pWprFile->RoutesHdr.wCurrentRoutes && cRt < c_cWprMaxRoutes; ++ cRt) {
			const WORD wIdx = pWprFile->RoutesHdr.wIdx [cRt];
			if (wIdx == 0xFFFF) {
				assert (pWprFile->RoutesHdr.btUsed [cRt] == 0x00);
				continue;
			}
			assert (pWprFile->RoutesHdr.btUsed [wIdx] == 0xFF);
			const CWprRoute & rt = pWprFile->Routes [wIdx];

			const size_t cPoints = __min (rt.wWaypoints, c_cWprMaxWaypointsInRoute);

			points_t points (cPoints);
			routepoints_t rpoints (cPoints);

			for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint) {
				const size_t cWptIdx = rt.wWptIdx [cPoint];
				const size_t cWptIdx2 = pWprFile->WptHdr.wIdx [cWptIdx];
				const CWprWaypoint & wpt = pWprFile->Waypoints [cWptIdx2];
				assert (wpt.wRoutesRefs != 0);

				points [cPoint].x =  wpt.lX/36000.f;
				points [cPoint].y = -wpt.lY/36000.f;

				rpoints [cPoint].pWaypoint = pWaypoints [cWptIdx2];
			}

			//
			// Create route.
			//

			rgn_t & rgn = _pMap->CreateRgn (rkPolyline);

			rgn.SetRouteType ();

			rgn.pFileRef  = & file_refs.back ();
			rgn.cBeginPos = reinterpret_cast<const char *> (& rt) - _pData;
			rgn.cEndPos   = reinterpret_cast<const char *> (pEnd) - _pData;
			rgn.cFileLine = -1;
		//	rgn.cOrdinal = m_cOrdinal ++;

			// Name.
			rgn.strLabel.assign   (rt.strName,    GetLineLen (rt.strName,    rt.strName    + sizeof (rt.strName)));
			// Comment.
			rgn.strComment.assign (rt.strComment, GetLineLen (rt.strComment, rt.strComment + sizeof (rt.strComment)));

			rgn.elements.push_back (rgn_element_t ());
			rgn_element_t & element = rgn.elements.back ();
			element.cFileOffset = rgn.cBeginPos;

			//
			element.cLevel = 0;
			element.points.swap (points);

			route_info_t * const pRouteExtra = rgn.pExtra->wtr.CreateRoute ();
			pRouteExtra->points.swap (rpoints);

			// Date and Time.
			const int nDay    =   rt.dwDate       & 0x1F;
			const int nMonth  = ((rt.dwDate >> 8) & 0xF);
			const int nYear   =  (rt.dwDate >> 16);

			const int nSecond =  rt.dwTime       % 60;
			const int nMinute = (rt.dwTime/60)   % 60;
			const int nHour   = (rt.dwTime/3600) % 60;

			SYSTEMTIME st = {nYear, nMonth, 0, nDay, nHour, nMinute, nSecond, 0};
			if (::SystemTimeToVariantTime (& st, & pRouteExtra->dtTime)) {
				pRouteExtra->dtTime += dtTimeShift;
				pRouteExtra->wFlags |= route_info_t::defTime;
			}

			SetProgressStatus (25 + 25*cRt/pWprFile->RoutesHdr.wCurrentRoutes);
		}
	}

	_pMap->file_refs.swap (file_refs);

	// Suppress warning about empty Zoom etc.
	_pMap->bNoHeader = true;
	_pMap->cHeaderLen = sizeof (CWprWaypointsHdr);

	SetProgressStatus (50);

	return lsOK;
}
